package com.m3958.firstgwt.server.model;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.persistence.AttributeOverride;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.Lob;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Query;
import javax.persistence.Table;
import javax.persistence.Transient;

import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;
import net.sf.json.util.CycleDetectionStrategy;

import org.apache.commons.lang.StringUtils;

import redis.clients.jedis.Jedis;

import com.m3958.firstgwt.client.types.ObjectRoleName;
import com.m3958.firstgwt.server.service.ObjectKeyValueProcessor;
import com.m3958.firstgwt.server.session.ErrorMessages;
import com.m3958.firstgwt.server.types.AppConstants;
import com.m3958.firstgwt.server.types.HasObjectPermission;
import com.m3958.firstgwt.server.types.HasRelation;
import com.m3958.firstgwt.server.types.HasTags;
import com.m3958.firstgwt.server.types.IHasSiteId;
import com.m3958.firstgwt.server.types.JsonExcludeFields;
import com.m3958.firstgwt.server.types.ObjectOperation;
import com.m3958.firstgwt.server.types.TreeModel;
import com.m3958.firstgwt.server.utils.CollectionFunc;
import com.m3958.firstgwt.server.utils.JsonlibDateValueProssor;
import com.m3958.firstgwt.server.utils.ModernPaginator;
import com.m3958.firstgwt.server.utils.ObjectPermissionUtil;
import com.m3958.firstgwt.server.utils.Paginator;
import com.m3958.firstgwt.server.utils.SimplePaginator;
import com.m3958.firstgwt.shared.type.CommonField;


@Entity
@Table(name="SECTIONS")
@AttributeOverride(name="id",column=@Column(nullable = false,name="SECTION_ID"))
@NamedQueries({
	@NamedQuery(name="findTopSectionByName",
			query="SELECT s FROM Section AS s WHERE s.siteId = :siteId AND s.name = :name AND s.parent IS NULL"),
	@NamedQuery(name="findTopSections",
			query="SELECT s FROM Section s WHERE s.siteId = :siteId AND s.parent IS NULL ORDER BY s.position ASC"),
	@NamedQuery(name="findSectionsByNameAndParent",
			query="SELECT s FROM Section s WHERE s.siteId = :siteId AND s.parent = :parent AND s.name = :name"),
	@NamedQuery(name="findSectionsByIds",
			query="SELECT s FROM Section s WHERE s.id IN :sectionIds"),
	@NamedQuery(name="getAllSections",
			query="SELECT s FROM Section s WHERE s.siteId = :siteId")			
})

public class Section extends BaseTreeModel<Section> implements TreeModel<Section>,HasCreator,HasObjectPermission,HasRelation,IHasSiteId,ObjectKeyValueProcessor.HasKeyValue,HasTags{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	public static class NamedQueries{
		public final static String FIND_TOP_BY_NAME = "findTopSectionByName";
		public final static String FIND_TOP = "findTopSections";
		public final static String FIND_VISIBLE_TOP = "findVisibleTopSections";
		public final static String FIND_BY_NAME_PARENT = "findSectionsByNameAndParent";
		public final static String FIND_BY_IDS = "findSectionsByIds";
		public final static String GET_ALL_SECTIONS = "getAllSections";
	}
	
	
	private static ObjectOperation[] possibleOperations;
	
	private static ObjectRoleName[] possibleObjectRoles = new ObjectRoleName[]{ObjectRoleName.CONTENT_ADDER,ObjectRoleName.CONTENT_AUDIT,ObjectRoleName.CONTENT_EDITOR,ObjectRoleName.CONTENT_READER,ObjectRoleName.OWNER,ObjectRoleName.READER};
	
	@Override
	public ObjectRoleName[] possibleRoleNames(){
		return possibleObjectRoles;
	}
	
	static{
		possibleOperations = ObjectOperation.values();
	}
	
	@Override
	public ObjectOperation[] possibleOperations(){
		return possibleOperations;
	}
	
	@Override
	public JSONObject toJson(){
		JsonConfig jc = new JsonConfig();
		jc.registerJsonValueProcessor(Date.class, injector.getInstance(JsonlibDateValueProssor.class));
		jc.setCycleDetectionStrategy(CycleDetectionStrategy.LENIENT);
		jc.setExcludes(JsonExcludeFields.SECTION_EXCLUDES);
		return JSONObject.fromObject(this, jc);
	}
	
	@Override
	public JSONObject toJson(String jsonv){
		if(jsonv != null && jsonv.length()>0){
			JsonConfig jc = new JsonConfig();
			jc.registerJsonValueProcessor(Date.class, injector.getInstance(JsonlibDateValueProssor.class));
			jc.setCycleDetectionStrategy(CycleDetectionStrategy.LENIENT);
			jc.setExcludes(CollectionFunc.arraySub(JsonExcludeFields.SECTION_EXCLUDES,"children"));
			
			JSONObject jo = JSONObject.fromObject(this, jc);
			String[] ts = new String[tags.size()];
			for(int i=0;i<ts.length;i++){
				ts[i] = tags.get(i).getName();
			}
			String s = StringUtils.join(ts, " ");
			jo.element(CommonField.TAG_NAMES.getValue(), s);
			return jo;
		}else{
			return toJson();
		}
	}
	
	
	private String tplName;
	
	private String name;
	
	private int siteId;
	
	private int perpage;
	
	private int position;
	
	private String protectLevel;
	
	@Lob
	private String htmlBlock;
	
	private boolean publicFlag;
	
	@Transient
	private Map<String, String> keyValueMap;
	
	@Lob
	private String keyValues;
	
	@ManyToOne(fetch=FetchType.LAZY)
	@JoinColumn(name = "parentId")
	private Section parent;
	
	@ManyToMany(fetch=FetchType.LAZY)
	@JoinTable(name="SECTION_ARTICLE")
	@OrderBy("publishedAt DESC")
	private List<Article> articles = new ArrayList<Article>();
	
	@OneToMany(mappedBy="parent")
	@OrderBy("position ASC")
	private List<Section> children = new ArrayList<Section>();
	
	@Override
	public Section getParent() {
		return parent;
	}
	
	/**
	 * 每个目录可以设定用户特殊用途的keyvalue对，"xx=6,yy=ok"，得到getValue("xx")将得到6.
	 * @param key
	 * @return value
	 */
	public String value(String key){
		String v = ObjectKeyValueProcessor.getValue(this, key);
		if(v.isEmpty() && this.getParent() != null){
			return this.getParent().value(key);
		}
		return v;
	}
	
	
	@ManyToMany(fetch=FetchType.LAZY)
	private List<Tag> tags = new ArrayList<Tag>();

	public void setTags(List<Tag> tags) {
		this.tags = tags;
	}

	public List<Tag> getTags() {
		return tags;
	}

	@Override
	public boolean addTag(Tag tag) {
		if(tags.contains(tag)){
			return false;
		}else{
			tags.add(tag);
			return true;
		}
	}
	
	@Override
	public boolean dropTag(Tag tag) {
		if(tags.contains(tag)){
			tags.remove(tag);
			return true;
		}else{
			return false;
		}
	}
	
	/**
	 * @return 兄弟节点，不包括自己
	 */
	@Override
	public List<Section> siblings(){
		List<Section> sbs = new ArrayList<Section>();
		if(getParent()!=null){
			for(TreeModel<Section> s:getParent().getChildren()){
				if( s != this){
					sbs.add((Section) s);
				}
			}
		}else{
			for(Section s : getSite(siteId).topSections()){
				if(s!=this){
					sbs.add(s);
				}
			}
		}
		return sbs;
	}
	
	public List<Section> hasTagsSiblings(List<String> tagNames){
		List<Section> ss = new ArrayList<Section>();
		for(Section s : siblings()){
			if(s.hasTags(tagNames))ss.add(s);
		}
		return ss;
	}
	
	
	public List<Section> hasTagsSiblingsIncludeMe(List<String> tagNames){
		List<Section> ss = new ArrayList<Section>();
		for(Section s : siblingsIncludeMe()){
			if(s.hasTags(tagNames))ss.add(s);
		}
		return ss;
	}

	
	/**
	 * @return 兄弟节点，包括自己
	 * 
	 */
	public List<Section> siblingsIncludeMe(){
		if(getParent()!=null){
			return getParent().getChildren();
		}else{
			return getSite(siteId).topSections();
		}
	}
	
	/**
	 * 面包屑，从顶层目录到自己的路径
	 * @return List<Section>
	 */
	public List<Section> breadCrumb(){
		List<Section> pp = new ArrayList<Section>();
		Section p = this;
		while(p!=null){
			pp.add(p);
			p = p.getParent();
		}
		Collections.reverse(pp);
		return pp;
	}


	protected String creatorIds;
	
	@ManyToOne
	@JoinColumn(name="CREATOR_ID",referencedColumnName="USER_ID")
	protected User creator;
	
	
	@Override
	public User getCreator() {
		return creator;
	}

	@Override
	public void setCreator(User creator) {
		this.creator = creator;
		creatorIds = getCreatorPath(creator);
	}

	@Override
	public String getCreatorIds() {
		return creatorIds;
	}
	
	
	public boolean hasArticles(){
		return articleCount() > 0;
	}
	
	public boolean hasChildrenArticles(){
		return childrenArticleCount() > 0;
	}
	
	public boolean hasOneArticle(){
		return articleCount() == 1;
	}

	/**
	 * 此目录的默认url路径，/section/55
	 * @return 此目录的url路径
	 */
	public String getUrl(){
		if(getSite(siteId).isSearchFriendUrl()){
			return getFriendUrl("section",getTplName(),getId());
		}else{
			return "/?" + AppConstants.TPL_PARAMETER_NAME + "=" + getTplName()+ "&" + AppConstants.OBNAME_PARAMETER_NAME + "=section&" + AppConstants.OBID_PARAMETER_NAME + "=" + id;
		}
	}
	
	/**
	 * @see #getUrl()
	 * 上面的方法返回的是默认的目录模板即：section，此方法可以指定任意的模板，比如getUrl("anotherTpl")，返回的路径就是：/section/55?tpl=anotherTpl
	 * @param tplName 模板名称
	 * @return 此目录的url路径
	 */
	public String getUrl(String tplName){
		if(getSite(siteId).isSearchFriendUrl()){
			return getFriendUrl("section",tplName,getId());
		}else{
			return "/?" + AppConstants.TPL_PARAMETER_NAME + "=" + tplName+ "&" + AppConstants.OBNAME_PARAMETER_NAME + "=section&" + AppConstants.OBID_PARAMETER_NAME + "=" + id;
		}
	}
	
	/**
	 * 得到<b>本目录</b>下的一页文章，按发布日期排倒序，页的大小是目录属性的一部分，可以在目录编辑页面设置。
	 * @param pageNum 第几页
	 * @return 一页文章
	 */
	public List<Article> articlePage(int pageNum,boolean recursive){
		if(recursive){
			return childrenArticlePage(pageNum);
		}
		if(pageNum < 1)pageNum = 1;
		return articles((pageNum-1)*getPerpage(), getPerpage());
	}
	
	
	public List<Article> articlePage(int pageNum){
		return articlePage(pageNum, false);
	}
	
	/**
	 * 得到本目录的<b>所有子目录中</b>的一页文章，按发布日期排倒序，页的大小是目录属性的一部分，可以在目录编辑页面设置。
	 * @param pageNum  第几页
	 * @return 一页文章
	 */
	public List<Article> childrenArticlePage(int pageNum){
		if(pageNum < 1)pageNum = 1;
		return childrenArticles((pageNum-1)*getPerpage(), getPerpage());
	}


	/**
	 * 简单分页器
	 * @param currentPage 此参数直接在模板里面提供，输入currentPage即可。
	 * @return 简单分页器
	 */
	public SimplePaginator simplePaginator(int currentPage,boolean recursive){
		if(recursive){
			return new SimplePaginator(childrenArticleCount(), getPerpage(), currentPage);
		}else{
			return new SimplePaginator(articleCount(), getPerpage(), currentPage);
		}
	}
	
	public SimplePaginator simplePaginator(int currentPage){
		return simplePaginator(currentPage, false);
	}
	
	public Paginator paginator(int currentPage,int pageWindow){
		return paginator(currentPage, pageWindow, false);
	}

	
	public Paginator paginator(int currentPage,int pageWindow,boolean recursive){
		if(recursive){
			return new Paginator(childrenArticleCount(),getPerpage(), pageWindow, currentPage);
		}else{
			return new Paginator(articleCount(),getPerpage(), pageWindow, currentPage);
		}
	}
	
	/**
	 * 现代化的分页器，此分页器的html是固定的，在java代码里面输出。
	 * @param currentPage 直接引用即可。
	 * @param pageWindow 显示的页数的一半，比如1,2,3,4,5,6,7,当前页是4的话，那么窗口的大小就是3.
	 * @param prepostPageNum 省略号前后的页数。比如：1,2...3,4,5,6,7,8,9...100,101,那么这个值就是2
	 * @param prename 前一页的显示：比如 《前一页
	 * @param postname 后一页的显示：比如：后一页》
	 * @param uriAndQs 直接引用即可。
	 * @return 现代分页器
	 */
	public ModernPaginator modernPaginator(int currentPage,int pageWindow,int prepostPageNum,String prename,String postname,String uriAndQs,boolean recursive){
		if(recursive){
			return new ModernPaginator(childrenArticleCount(), getPerpage(), pageWindow, prepostPageNum, currentPage,prename,postname,uriAndQs);
		}else{
			return new ModernPaginator(articleCount(), getPerpage(), pageWindow, prepostPageNum, currentPage,prename,postname,uriAndQs);
		}
	}
	
	public ModernPaginator getModernPaginator(int currentPage,int pageWindow,int prepostPageNum,String prename,String postname,String uriAndQs){
		return modernPaginator(currentPage,pageWindow,prepostPageNum,prename,postname,uriAndQs,false);
	}

	
	/**
	 * 目录的文章，从0开始，按发布日期逆向排序。
	 * @param num
	 * @return 目录的文章，从0开始，按发布日期逆向排序。
	 */
	public List<Article> articles(int num){
		return articles(0, num);
	}
	/**
	 * 目录的文章，从start开始，按发布日期逆向排序。
	 * @param start
	 * @param num
	 * @return 目录的文章，从start开始，按发布日期逆向排序。
	 */
	public List<Article> articles(int start,int num){
		List<Article> ars = new ArrayList<Article>();
		Query q = emp.get().createNamedQuery(Article.NamedQueries.GET_SECTION_ARTICLE);
		q.setParameter("section", this);
		q.setParameter("audit", true);
		q.setFirstResult(start);
		q.setMaxResults(num);
		ars =  q.getResultList();
		return ars;
	}
	/**
	 * 子目录的文章，从0开始
	 * @param num
	 * @return 子目录的文章，从0开始
	 */
	public List<Article> childrenArticles(int num){
		return childrenArticles(0, num);
	}

	/**
	 * 子目录的文章，从start开始
	 * @param start
	 * @param num
	 * @return 子目录的文章，从start开始
	 */
	public List<Article> childrenArticles(int start,int num){
		if(isFolder()){
			List<Article> ars = new ArrayList<Article>();
			Query q = emp.get().createNamedQuery(Article.NamedQueries.GET_SECTION_CHILDREN_ARTICLE);
			q.setParameter("sectionId", "%," + this.getId() + ",%");
			q.setParameter("audit", true);
			q.setFirstResult(start);
			q.setMaxResults(num);
			ars =  q.getResultList();
			return ars;
		}else{
			return articles(start, num);
		}
	}
	
	public int childrenArticleCount(){
		if(isFolder()){
			Query q = emp.get().createNamedQuery(Article.NamedQueries.SECTION_CHILDREN_ARTICLE_COUNT);
			q.setParameter("sectionId", "%," + this.getId() + ",%");
			q.setParameter("audit", true);
			Long c =  (Long) q.getSingleResult();
			return c.intValue();
		}else{
			return articleCount();
		}
	}

	
	public int articleCount(){
		Query q = emp.get().createNamedQuery(Article.NamedQueries.SECTION_ARTICLE_COUNT);
		q.setParameter("section", this);
		q.setParameter("audit", true);
		Long c =  (Long) q.getSingleResult();
		return c.intValue();
	}
	
	
	public List<Article> searchPage(String tkw,String ckw,boolean isAnd ,int pageNum){
		return searchArticles(tkw,ckw,isAnd,(pageNum - 1)*getPerpage(),getPerpage());
	}
	

	public SimplePaginator searchPaginator(String tkw,String ckw,boolean isAnd,int currentPage){
		SimplePaginator spt = new SimplePaginator(searchCount(tkw,ckw,isAnd), getPerpage(), currentPage);
		return spt;
	}

	
	public List<Article> searchArticles(String tkw,String ckw,boolean isAnd, int num){
		return searchArticles(tkw,ckw,isAnd, 0,num);
	}
	
	public List<Article> searchArticles(String tkw,String ckw,boolean isAnd ,int start,int num){
		Query q;
		boolean hasEmpty = tkw == null || tkw.isEmpty() || ckw == null || ckw.isEmpty();
		if(isFolder()){
			if(isAnd){
				q = emp.get().createNamedQuery(Article.NamedQueries.SEARCH_SECTION_CHILDREN_ARTICLE_AND);
			}else{
				q = emp.get().createNamedQuery(Article.NamedQueries.SEARCH_SECTION_CHILDREN_ARTICLE_OR);
			}
			if(hasEmpty)q = emp.get().createNamedQuery(Article.NamedQueries.SEARCH_SECTION_CHILDREN_ARTICLE_AND);
			q.setParameter("sectionId", "%," + this.getId() + ",%");
		}else{
			if(isAnd){
				q = emp.get().createNamedQuery(Article.NamedQueries.SEARCH_SECTION_ARTICLE_AND);
			}else{
				q = emp.get().createNamedQuery(Article.NamedQueries.SEARCH_SECTION_ARTICLE_OR);
			}
			q = emp.get().createNamedQuery(Article.NamedQueries.SEARCH_SECTION_ARTICLE_AND);
			q.setParameter("section", this);			
		}
		
		String ttkw = "%" + tkw + "%";
		String cckw = "%" + ckw + "%";
		
		q.setParameter("audit", true);
		q.setParameter("title", ttkw);
		q.setParameter("content", cckw);
		q.setFirstResult(start);
		q.setMaxResults(num);
		List<Article> ars =  q.getResultList();
		return ars;
	}
	
	public int searchCount(String tkw,String ckw,boolean isAnd){
		Query q;
		if(isFolder()){
			if(isAnd){
				q = emp.get().createNamedQuery(Article.NamedQueries.SEARCH_SECTION_CHILDREN_ARTICLE_COUNT_AND);
			}else{
				q = emp.get().createNamedQuery(Article.NamedQueries.SEARCH_SECTION_CHILDREN_ARTICLE_COUNT_OR);
			}
			q.setParameter("sectionId", "%," + this.getId() + ",%");
		}else{
			if(isAnd){
				q = emp.get().createNamedQuery(Article.NamedQueries.SEARCH_SECTION_ARTICLE_COUNT_AND);
			}else{
				q = emp.get().createNamedQuery(Article.NamedQueries.SEARCH_SECTION_ARTICLE_COUNT_OR);
			}
			q.setParameter("section", this);
		}
		String ttkw = "%" + tkw + "%";
		String cckw = "%" + ckw + "%";
		q.setParameter("audit", true);
		q.setParameter("title", ttkw);
		q.setParameter("content", cckw);
		return ((Long) q.getSingleResult()).intValue();
	}


	
	@OneToMany(fetch=FetchType.LAZY,cascade={CascadeType.PERSIST,CascadeType.REMOVE})
	@JoinTable(name="SECTION_OBJECTPERMISSION")
	private List<Permission> objectPermissions = new ArrayList<Permission>();
	
	
	@OneToMany(fetch=FetchType.LAZY,cascade={CascadeType.PERSIST,CascadeType.REMOVE})
	@JoinTable(name="SECTION_OBJECTROLE")
	private List<Role> objectRoles = new ArrayList<Role>();
	
	@Override
	public List<Permission> objectPermissions() {
		return objectPermissions;
	}

	@Override
	public void setObjectPermissions(List<Permission> permissions) {
		this.objectPermissions = permissions;
	}
	
	
	@Override
	public void createObjectPermissions(){
		ObjectPermissionUtil.createObjectPermissions(this);
	}
	
	
	
	@Override
	public void createObjectRoles(){
		ObjectPermissionUtil.createObjectRoles(this);
	}
	
	@Override
	public Role createObjectRole(ObjectRoleName orn){
		return ObjectPermissionUtil.createObjectRole(this, orn);
	}
	
	@Override
	public Role objectRole(ObjectRoleName orn){
		return ObjectPermissionUtil.getObjectRole(this, orn);
	}
	
	public void setObjectRoles(List<Role> roles) {
		this.objectRoles = roles;
	}

	@Override
	public List<Role> objectRoles() {
		return objectRoles;
	}
	
	@Override
	public boolean addObjectRole(Role r){
		return ObjectPermissionUtil.addObjectRole(objectRoles, r);
	}
	
	@Override
	public boolean addObjectPermission(Permission p){
		return ObjectPermissionUtil.addObjectPermission(objectPermissions, p);
	}

	@Override
	public String getOname() {
		return name;
	}
	
	@Override
	public Permission permission(ObjectOperation opCode) {
		return ObjectPermissionUtil.getPermission(this, opCode);
	}

	public void setArticles(List<Article> articles) {
		this.articles = articles;
	}

	public List<Article> getArticles() {
		List<Article> ars = new ArrayList<Article>();
		for(Article a : articles){
			if(a.isAudit())ars.add(a);
		}
		return ars;
	}

	@Override
	public boolean manageRelation(BaseModel bm, boolean isAdd, String hint,
			ErrorMessages errors) {
		boolean success = false;
		if(isAdd){
			if(bm instanceof Article){
				if(articles.contains(bm)){
					;
				}else{
					articles.add((Article) bm);
					success = true;
				}
			}
		}else{
			if(bm instanceof Article){
				if(articles.contains(bm)){
					articles.remove(bm);
					success = true;
				}else{
					;
				}
			}
		}
		if(success){
			clearCache();
			WebSite ws = emp.get().find(WebSite.class, getSiteId());
			if(ws != null)ws.clearHomePageCache();
		}
		return success;
	}
	
	public void clearCache(){
		Jedis jd = jpservice.getInstance();
		try {
			String obid = this.getSiteId() + ",section," + getId();
			String etag = jd.get(obid);
			if(etag != null){
				String jurls = jd.get(etag);
				if(jurls != null)
					jd.del(jurls);
				jd.del(etag);
			}
			Section ps =getParent();
			while (ps != null) {
				ps.clearCache();
				ps = ps.getParent();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			jpservice.putBack(jd);
		}
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}
	
	public String getName(int length){
		if(name != null && name.length() > length){
			return name.substring(0,length);
		}else{
			return name;
		}
	}
	
	public String getName(int length,String postFix){
		if(name != null && name.length() > length){
			return name.substring(0,length -1) + postFix;
		}else{
			return name;
		}
	}


	@Override
	public void setSiteId(int siteId) {
		this.siteId = siteId;
	}

	@Override
	public int getSiteId() {
		return siteId;
	}


	public void setKeyValueMap(Map<String, String> keyValueMap) {
		this.keyValueMap = keyValueMap;
	}

	public Map<String, String> getKeyValueMap() {
		return keyValueMap;
	}

	public void setKeyValues(String keyValues) {
		this.keyValues = keyValues;
	}

	public String getKeyValues() {
		return keyValues;
	}

	public void setPosition(int position) {
		this.position = position;
	}

	public int getPosition() {
		return position;
	}

//	public void setHidden(boolean hidden) {
//		this.hidden = hidden;
//	}
//
//	public boolean getHidden() {
//		return hidden;
//	}

	public String getTplName() {
		if(tplName == null || tplName.isEmpty())return "section";
		return tplName;
	}

	public void setTplName(String tplName) {
		this.tplName = tplName;
	}

	public void setPerpage(int perpage) {
		this.perpage = perpage;
	}

	public int getPerpage() {
		if(perpage == 0)return 20;
		return perpage;
	}
	
	public boolean getIsRoot(){
		if(getParent() == null)return true;
		return false;
	}

//	public void setSectionContainer(boolean sectionContainer) {
//		this.sectionContainer = sectionContainer;
//	}
//
//	public boolean isSectionContainer() {
//		return sectionContainer;
//	}

	public void setProtectLevel(String protectLevel) {
		this.protectLevel = protectLevel;
	}

	public String getProtectLevel() {
		return protectLevel;
	}

	@Override
	public List<Section> getChildren() {
		return children;
	}

	@Override
	public void setChildren(List<Section> children) {
		this.children = children;
	}

	@Override
	public void setParent(Section parent) {
		this.parent = parent;
		setParentExtra();
	}

	public void setPublicFlag(boolean publicFlag) {
		this.publicFlag = publicFlag;
	}

	public boolean isPublicFlag() {
		return publicFlag;
	}

	@Override
	public String[] getJsonExcludes() {
		return null;
	}
	
	@Override
	public boolean hasTag(String tagName) {
		for(Tag t : getTags()){
			if(t.getName().equals(tagName)){
				return true;
			}
		}
		return false;
	}

	@Override
	public boolean hasTags(List<String> tagNames) {
		for(String tagName : tagNames){
			boolean foundOne = false;
			for(Tag t : getTags()){
				if(t.getName().equals(tagName)){
					foundOne = true;
					break;
				}
			}
			if(!foundOne){
				return false;
			}
		}
		return true;
	}

	public String getHtmlBlock() {
		return htmlBlock;
	}

	public void setHtmlBlock(String htmlBlock) {
		this.htmlBlock = htmlBlock;
	}
}
